package com.wiselink.coupang;

import com.coupang.openapi.sdk.Hmac;
import com.wiselink.exception.CoupangException;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * 酷澎API基础类
 */
public class CoupangBaseAPI {
    protected static final Logger log = LoggerFactory.getLogger(CoupangBaseAPI.class);

    protected static final String SCHEMA = "https";
    protected static final String HOST = "api-gateway.coupang.com";
    protected static final int PORT = 443;
    protected static final String URL = SCHEMA + "://" + HOST + ":" + PORT;

    protected static final MediaType mediaType = MediaType.parse("application/json; charset=utf-8");

    protected static final OkHttpClient client = new OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).build();

    public enum Method {
        POST,
        GET,
        PUT,
        DELETE;
    }

    /**
     * HMAC Signature创建
     * <p>
     * 什么是 HMAC？为什么需要HMAC？
     * HMAC是信息认证代码(keyed-hash message authentication code)的缩写，是 RFC2014  标准密钥协议相关的代码。
     * <p>
     * 目前，酷澎openAPI 是基于HMAC制作的，您须一并发送所有在request header 'Authorization' 中生成的 HMAC signature。
     */
    public static String generateHMACSignature(String method, String uri, ShopVO vo) {
        return Hmac.generate(method, uri, vo.getShopKey(), vo.getShopSecret());
    }

    /**
     * 发送请求
     *
     * @param authorization authorization
     * @param path          path
     * @param reqBody       reqBody
     * @param mark          mark
     * @param method        method
     * @return 响应结果
     */
    protected static String executeRequest(String authorization, String path, String reqBody, String mark, Method method) {
        RequestBody body;

        Request.Builder builder = new Request.Builder()
                .url(URL + path)
                .addHeader("Authorization", authorization);

        switch (method) {
            case GET:
                builder.get();
                break;
            case DELETE:
                builder.delete();
                break;
            case POST:
                body = RequestBody.create(mediaType, reqBody);
                builder.post(body);
                builder.addHeader("content-type", "application/json");
                break;
            case PUT:
                body = RequestBody.create(mediaType, reqBody);
                builder.put(body);
                builder.addHeader("content-type", "application/json");
                break;
        }

        Request request = builder.build();

        try (Response response = client.newCall(request).execute()) {
            int code = response.code();
            log.debug("HTTP {} response code: {}", method, code);

            String bodyStr = null;
            if (response.body() != null) {
                try (ResponseBody responseBody = response.body()) {
                    bodyStr = responseBody.string();
                } catch (IOException e) {
                    log.error("{} response body read error", mark, e);
                    throw new CoupangException(mark + " response body read error", e);
                }
            }

            log.debug("Response body (truncated): {}", truncateLogMessage(bodyStr));

            if (code == 200) {
                return bodyStr;
            }
            throw new CoupangException(String.format("%s fail, reason: %s", mark, bodyStr));
        } catch (IOException e) {
            log.error("{} request error", mark, e);
            throw new CoupangException(mark + " request error", e);
        }
    }

    /**
     * 截断过长的日志内容
     *
     * @param message 日志内容
     * @return 截断过长的日志内容
     */
    private static String truncateLogMessage(String message) {
        if (message == null || message.length() <= 1000) {
            return message;
        }
        return message.substring(0, 1000) + "...[truncated]";
    }
}
